# calc.pyw                                       David MacQuigg  ece373  11/7/07
'''A Multi-Hetero-Generic calculator.  Add, Subtract, Multiply or Divide,
numbers, polynomials, matrices, whatever.'''

'''modified by Phillip Toussaint to implement an interface useable for
RPN, and to be complient with our project specifications
'''

# 0.2 Added stack display
# 0.1 Starting with John Zelle's calculator (Ch.11 in Python Programming)

import sys
from graphics import *
from button import Button
from stackdisplay import StackDisplay
from ModTranslator import Translator
class Calculator:
    # This class implements a simple calculator GUI

    def __init__(self):
        # create the window for the calculator
        win = GraphWin("calculator", height=400, width=400)
        win.setCoords(0,0,7,14)
        win.setBackground("slategray")
        self.win = win
        # Now create the widgets
        self.__createButtons()
        self.__createDisplay()
        self.stackVisible = False
        self.mathsys = Translator(self)
        self.numText = ""
        self.typeText = "N: "
        self.display.setText(self.typeText + self.numText)

    def __createButtons(self):
        # create list of buttons
        # start with all the standard sized buttons
        # bSpecs gives center coords and label of buttons
        bSpecs = [(1,1,':'), (2,1,']'), (3,1,'}'),
                  (1,2,','), (2,2,'['), (3,2,'{'), (4,2,'/'), (5,2,'m'),
                  (1,3,'S'), (2,3,'0'), (3,3,'.'), (4,3,'-'), (5,3,'Q'), (6,3,'L'),
                  (1,4,'1'), (2,4,'2'), (3,4,'3'), (4,4,'+'), (5,4,'N'), (6,4,'M'),
                  (1,5,'4'), (2,5,'5'), (3,5,'6'), (4,5,'*'), (5,5,'I'), (6,5,'P'),
                  (1,6,'7'), (2,6,'8'), (3,6,'9'), (4,6,'<-'), (5,6,'C'), (6,6,'#')]
        self.buttons = []
        for cx,cy,label in bSpecs:
            self.buttons.append(Button(self.win,Point(cx,cy),.75,.75,label))
        # create the larger = button
        self.buttons.append(Button(self.win, Point(4.5,1), 1.75, .75, "ENT"))
        # activate all buttons
        for b in self.buttons:
            b.activate()

    def __createDisplay(self):
        bg = Rectangle(Point(.5,7.55), Point(6.5,8.45))
        bg.setFill('white')
        bg.draw(self.win)
        text = Text(Point(3,8), "")
        text.draw(self.win)
        text.setFace("courier")
        text.setStyle("bold")
        text.setSize(16)
        self.display = text
        self.stackdisplay={}
        for i in range(5):
            bg = Rectangle(Point(.5, 8.55+ i), Point(6.5,9.45+i))
            bg.setFill('white')
            bg.draw(self.win)
            text = Text(Point(3,9+i), "")
            text.draw(self.win)
            text.setFace("courier")
            text.setStyle("bold")
            text.setSize(16)
            self.stackdisplay[i] = text

    def getButton(self):
        # Waits for a button to be clicked and returns the label of
        #    the button that was clicked.
        while True:
            p = self.win.getMouse()
            for b in self.buttons:
                if b.clicked(p):
                    return b.getLabel() # method exit

    def processButton(self, key):
        # Updates the display of the calculator for press of this key
        text = self.display.getText()
        if key == 'S':   # show or hide stack
            if self.stackVisible == False:
                self.stackwin = StackDisplay(30, regList)
                self.stackVisible = True
            else:
                self.stackwin.close()
                self.stackVisible = False
        elif key == 'C':
            self.mathsys.sendChar("C")
        elif key == '<-':
            # Backspace, slice off the last character.
            self.display.setText(text[:-1])
        elif key == 'ENT':
            # Evaluate the expresssion and display the result.
            # the try...except mechanism "catches" errors in the
            # formula being evaluated.
            self.mathsys.sendChar("E")
        elif key == '+':
            self.mathsys.sendChar("+")
        elif key == '*':
            self.mathsys.sendChar("*")
        elif key == 'I':
            self.mathsys.sendChar("I")
        elif key == 'N':
            self.mathsys.sendChar("N")
        elif key == '-':
            self.mathsys.sendChar("-")
        elif key == '/':
            self.mathsys.sendChar("/")
        elif key == 'Q':
            self.mathsys.sendChar("Q")
        elif key == 'm':
            self.mathsys.sendChar("M")
        elif key == '#':
            self.typeText = "N: "
            self.display.setText(self.typeText + self.numText)
        elif key == 'P':
            self.typeText = "P: "
            self.display.setText(self.typeText + self.numText)
        elif key == 'M':
            self.typeText = "M: "
            self.display.setText(self.typeText + self.numText)
        elif key == 'L':
            self.typeText = "L: "
            self.display.setText(self.typeText + self.numText)
        else:
            # Normal key press, append it to the end of the display
            self.numText = self.numText + key
            self.display.setText(self.typeText + self.numText)

    def run(self):
        # Infinite 'event loop' to process button clicks.
        while True:
            key = self.getButton()
            self.processButton(key)

    def getText(self):
        return self.numText

    def getType(self):
        return self.typeText

    def clearScreen(self):
        self.numText = ""
        self.display.setText(self.typeText + self.numText)

    def setStack(self, index, value):
        self.stackdisplay[index].setText(value)
        if self.stackVisible:
            self.stackwin.setStack(index, value)

if __name__ == '__main__':

    # Sample data.  Various structures that might be useful for representing
    # polynomials, matrices, etc.
    dict1 = {1:10, 3:30}             # A polynomial
    list1 = [[4,5,6,7],[8,9,10,11]]  # A matrix
    regList = [1,2.1,3+2j,dict1,list1]    # 5 items here
    
    # First create a calculator object
    calc = Calculator()
    # Now call the calculator's run method.
    calc.run()

        
        


